在討論物件引用前先探討call by value與call by reference的差別。
let message = "Hello!";
let phrase = message;
message = "Hello world!"
console.log(message); //Hello world
console.log(phrase); //Hello!
圖片來源: https://zh.javascript.info/object-copy
以上面為例子,把message指定成"Hello"時,message會在記憶體中儲存"Hello"(ex. 0x001),這時候把phrase指定為message,phrase會在記憶體中找到另一個獨立的位置(ex. 0x002)儲存"Hello",也就是說message與phrase是獨立的,不互相影響。
let user = {
name: "John"
};
let admin = user;
admin.name = 'Peter';
console.log(user.name) // 'Peter'
當我們把user指定為一個Object時,user會在記憶體中找到一個位子(ex. 0x003),這時候user變數儲存的不是object,而是object的引用,此時把admin指定為user,這時候跟call by value不同的是admin不會獨立找一個記憶體位置,而是複製了user對於object的引用,所以當這個object變動時,所有有引用的變數都會受到影響。
主要依賴這兩個method會返回一個新的數組的特性:
let a = [1,2,3,4]
let b = a.slice(0)
console.log(a === b); // false
b.push(5); // a = [1,2,3,4] b = [1,2,3,4,5]
深複製的方法皆適用於淺複製。
let a = [[0,0],[1,1]]
let b = Array.from(a)
a.push([2,2]) // a = [[0,0],[1,1],[2,2]] b = [[0,0],[1,1]]
let a = [[0,0],[1,1]]
let b = [...a]
a.push([2,2]) // a = [[0,0],[1,1],[2,2]] b = [[0,0],[1,1]]
let a = [[0,0],[1,1]];
let b = Object.assign([],a);
a.push([2,2]) // a = [[0,0],[1,1],[2,2]] b = [[0,0],[1,1]]
let a = [[0,0],[1,1]];
let b = JSON.parse(JSON.stringify(a));
a.push([2,2]) // a = [[0,0],[1,1],[2,2]] b = [[0,0],[1,1]]
展開符在array是深層複製,但是對於object來說是屬於淺複製,只有第一層是真正的複製,其他內層都是複製reference。
let person = {
height:180,
weight:70,
score: {
JavaScript: 100,
PHP: 80,
Python: 70
}
}
let clonePerson = {...person}
clonePerson.height = 190; // person身高不受影響
clonePerson.score.Java = 60; // 深層的部分並沒有複製,所以會影響到person.score
與方法一相同,只有在第一層是真正有複製到。
let person = {
height:180,
weight:70,
score: {
JavaScript: 100,
PHP: 80,
Python: 70
}
}
let clonePerson = Object.assign({},person)
clonePerson.height = 190; // person身高不受影響
clonePerson.score.Java = 60; // 深層的部分並沒有複製,所以會影響到person.score
let person = {
height:180,
weight:70,
score: {
JavaScript: 100,
PHP: 80,
Python: 70
}
}
let clonePerson = JSON.parse(JSON.stringify(person));
clonePerson.height = 190; // person身高不受影響
clonePerson.score.Java = 60; // 深層的部分也有複製,所以一樣不會影響到person.score
參考資料:
談談 JavaScript 中 by reference 和 by value 的重要觀念
JavaScript Info
複製 Array / Object 的幾種常用方法(深/淺拷貝)